Skip to content

Conversation

@thlorenz
Copy link
Contributor

@thlorenz thlorenz commented Oct 26, 2025

Summary

This PR integrates Helius Laser gRPC as a new endpoint option for real-time account subscriptions, providing a more reliable and efficient alternative to WebSocket-based pubsub connections. It also adds a fully automated manual test suite to validate the integration end-to-end.

Details

Helius Laser gRPC Integration

The main change introduces support for Helius Laser gRPC endpoints as an alternative to WebSocket pubsub connections. This is particularly beneficial for high-reliability deployments where stable, long-lived connections are critical.

  • ChainLaserClientImpl: New gRPC-based client implementation using the helius-laserstream crate
  • ChainUpdatesClient: Unified enum that selects between WebSocket and Laser clients based on URL pattern
  • Endpoint parsing: Added API key extraction from URLs for Helius endpoints
  • Connection multiplexing: Laser connections avoid multiplexing since they're more stable

Sample Configuration

To use Helius Laser gRPC, configure your validator with:

[accounts]
remote.url = "https://devnet.helius-rpc.com/?api-key=YOUR_HELIUS_API_KEY"
remote.ws-url = ["https://laserstream-devnet-ewr.helius-rpc.com?api-key=YOUR_HELIUS_API_KEY"]

[rpc]
addr = "0.0.0.0"
port = 9988

For mainnet, use the mainnet endpoints instead of devnet ones.

Manual Test Suite

A comprehensive manual test suite (test-manual/) validates the laser gRPC integration:

  • helius-laser: End-to-end test that performs SOL transfers on devnet and verifies account state synchronization between Helius RPC and the local validator
  • Automated setup: The test automatically starts a local validator, performs blockchain operations, and compares account states
  • Integration validation: Ensures the validator correctly clones accounts and maintains synchronized state via laser streams

Technical Improvements

  • Improved subscription update handling with unified SubscriptionUpdate struct
  • Added proper error handling and logging for laser operations

Deps

  • created fork of laser-sdk that downgrades yellowstone deps to be compat with our validator

Summary by CodeRabbit

  • New Features

    • Helius Laser gRPC support for per-account subscriptions and automatic backend selection; new endpoint helpers for pubsub URL/API-key handling.
  • Improvements

    • Unified subscription update format and more robust startup/shutdown/error flows (shutdown now reports errors).
    • WS vs GRPC multiplexing behavior refined and API-key extraction.
    • Reduced default subscribed-accounts LRU capacity.
  • Tests

    • Manual end-to-end test harness, Makefile targets, and documentation for Laser integration.

@github-actions
Copy link

github-actions bot commented Oct 26, 2025

Manual Deploy Available

You can trigger a manual deploy of this PR branch to testnet:

Deploy to Testnet 🚀

Alternative: Comment /deploy on this PR to trigger deployment directly.

⚠️ Note: Manual deploy requires authorization. Only authorized users can trigger deployments.

Comment updated automatically when the PR is synchronized.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 26, 2025

Walkthrough

Adds Helius Laserstream support and a multiplexing pubsub client: new Laser actor/client, ChainUpdatesClient enum (WS vs Laser), shared pubsub_common types, Endpoint helpers and GRPC detection, ChainPubsubClient.shutdown now returns Result, workspace/test tooling, and updated consumers to use ChainUpdatesClient.

Changes

Cohort / File(s) Summary
Workspace & manifests
Cargo.toml, magicblock-chainlink/Cargo.toml, test-manual/Cargo.toml, test-manual/helius-laser/Cargo.toml
Added helius-laserstream workspace dependency and new test workspace members / manifests for manual helius-laser tooling.
Laser infra & multiplexing
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs, .../chain_laser_client.rs, .../chain_updates_client.rs
New ChainLaserActor and ChainLaserClientImpl; new ChainUpdatesClient enum that selects/delegates to WebSocket (ChainPubsubClientImpl) or Laser client and implements ChainPubsubClient with endpoint-based selection.
Shared pubsub types
magicblock-chainlink/src/remote_account_provider/pubsub_common.rs
New shared types: PubsubClientConfig, SubscriptionUpdate (From<(Pubkey,RpcResponse)>), AccountSubscription, ChainPubsubActorMessage, and channel-size constants.
Actor/client refactor & errors
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs, .../chain_pubsub_client.rs, .../errors.rs, .../mod.rs
Moved types into pubsub_common; refactored actor shutdown to use cancellation token/function; ChainPubsubClient::shutdown now returns RemoteAccountProviderResult<()>; added MissingApiKey and ChainLaserActorSendError error variants; Endpoint helpers added; provider wiring now uses ChainUpdatesClient.
Chainlink & consumers updated
magicblock-chainlink/src/chainlink/mod.rs, magicblock-api/src/magic_validator.rs, magicblock-aperture/src/state/mod.rs, magicblock-accounts/src/scheduled_commits_processor.rs, test-integration/test-chainlink/src/ixtest_context.rs
Replaced SubMuxClient<ChainPubsubClientImpl> with SubMuxClient<ChainUpdatesClient> across type aliases, signatures and imports; adjusted endpoint construction call sites.
SubMux, debounce & tests
magicblock-chainlink/src/submux/mod.rs, .../debounce_state.rs, .../testing/chain_pubsub.rs, test-integration/**, test-integration/test-chainlink/tests/**
Consumers adapted to use SubscriptionUpdate.slot/account instead of rpc_response.*; SubMuxClient shutdown returns Result; tests and helpers updated (new shutdown helper, lamports/clock access, slot assertions).
External config (pubsub endpoint derivation)
magicblock-api/src/external_config.rs
Added is_grpc_url (delegates to is_helius_laser_url) and logic to detect GRPC (Laser) vs WS for deriving pubsub endpoints; adjusted ws URL generation and multiplexing behavior.
Manual integration tooling
test-manual/Makefile, test-manual/README.md, test-manual/helius-laser/src/main.rs, test-manual/rustfmt*.toml
Added manual-test-laser Makefile target, README, a helius-laser binary for manual validation flows, and rustfmt configs for the manual test workspace.
Config constant change
magicblock-chainlink/src/remote_account_provider/config.rs
Reduced DEFAULT_SUBSCRIBED_ACCOUNTS_LRU_CAPACITY from 10_000 to 7_000.

Sequence Diagram(s)

sequenceDiagram
    participant App as Consumer (Chainlink)
    participant CUC as ChainUpdatesClient
    participant WS as ChainPubsubClientImpl
    participant Laser as ChainLaserClientImpl

    App->>CUC: try_new_from_endpoint(endpoint)
    alt endpoint is Helius Laser (gRPC)
        CUC->>Laser: new_from_url(pubsub_url, api_key)
        Laser-->>CUC: initialized
    else WebSocket
        CUC->>WS: try_new_from_url(pubsub_url)
        WS-->>CUC: initialized
    end

    App->>CUC: subscribe(pubkey)
    alt using Laser
        CUC->>Laser: subscribe(pubkey)
        Laser->>Laser: spawn per-account streams
    else using WS
        CUC->>WS: subscribe(pubkey)
        WS->>WS: spawn per-account streams
    end

    note over Laser,WS: backends emit SubscriptionUpdate(pubkey, slot, account)
    Laser-->>CUC: SubscriptionUpdate
    WS-->>CUC: SubscriptionUpdate

    App->>CUC: shutdown()
    CUC->>WS: shutdown()
    CUC->>Laser: shutdown()
    WS-->>CUC: Ok(())
    Laser-->>CUC: Ok(())
    CUC-->>App: Ok(())
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Areas needing focused review:
    • chain_laser_actor.rs: per-account stream lifecycle, StreamMap usage, parsing, and shutdown coordination.
    • chain_laser_client.rs & chain_updates_client.rs: endpoint selection, API-key extraction, delegation, and take_updates semantics.
    • pubsub_common::SubscriptionUpdate::From conversion: decoding UiAccount -> Account and slot extraction.
    • Trait signature change for shutdown: ensure all callers handle RemoteAccountProviderResult<()>.
    • external_config.rs: GRPC detection and ws_url derivation (scheme/port/multiplex behavior).
    • Tests: updated assertions, helpers, and new shutdown helper.

Possibly related PRs

Suggested reviewers

  • GabrielePicco
  • Dodecahedr0x
  • bmuddha

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.81% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "feat: support helius laser GRPC client for cloning" directly and clearly describes the primary change in the changeset. The raw summary confirms that the main objectives are adding ChainLaserClientImpl (a gRPC-based client implementation), introducing ChainUpdatesClient to multiplex between WebSocket and Laser clients, and enabling Laser as an alternative endpoint option for account subscriptions. The title is specific about what is being added (helius laser GRPC client), identifies the technology (GRPC), and indicates the purpose (cloning). It is concise, uses the conventional "feat:" prefix, and provides sufficient clarity for developers scanning the commit history to understand the primary change without ambiguity.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch thlorenz/laser-grpc

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c0741de and e646942.

📒 Files selected for processing (1)
  • magicblock-chainlink/src/remote_account_provider/config.rs (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
🔇 Additional comments (1)
magicblock-chainlink/src/remote_account_provider/config.rs (1)

6-6: I need to gather more context about the motivation for this capacity change. Let me search for related information:

Let me search for more specific context in the codebase about performance or memory considerations:

Based on my analysis of the codebase and available information, I cannot find explicit documentation or metrics explaining the 30% capacity reduction. While the script output shows the constant is used consistently throughout the codebase and there's a TODO to make it configurable, there's no evidence in the code, comments, or documentation about:

  1. Performance benchmarks comparing 10,000 vs 7,000 capacity
  2. Memory profiling data justifying this specific reduction
  3. Whether this change was tested under production-like load conditions
  4. Clear connection to the Laser gRPC integration or specific constraints it introduced

Address the lack of documentation for the LRU capacity change.

The constant has been reduced from 10,000 to 7,000 without explanation in code comments or PR documentation. This significant change affects default behavior for all deployments and could increase cache evictions if the smaller capacity becomes a bottleneck under load.

Please provide:

  • Performance or memory profiling data that validates this specific value
  • Whether load testing was conducted to measure cache hit rate impact
  • Confirmation that 7,000 adequately handles typical subscription loads with the Laser gRPC integration

Consider adding an inline comment documenting the rationale (e.g., memory constraints, empirical performance testing results), or prioritize issue #577 to make this value configurable so teams can tune it for their deployments.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@thlorenz thlorenz force-pushed the thlorenz/laser-grpc branch from 479d26c to ba3580b Compare October 26, 2025 16:34
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 27

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
magicblock-chainlink/src/submux/mod.rs (5)

503-505: Potential panic: division by zero when debounce interval is 0ms.

allowed_in_debounce_window_count divides detection_window by debounce_interval without guarding zero. Config can set interval_millis to 0, causing a runtime panic.

Apply a clamp to avoid zero and keep semantics predictable:

 fn allowed_in_debounce_window_count(&self) -> usize {
-    (self.debounce_detection_window.as_millis()
-        / self.debounce_interval.as_millis()) as usize
+    let num = self.debounce_detection_window.as_millis();
+    let denom = self.debounce_interval.as_millis().max(1); // clamp to 1ms
+    (num / denom) as usize
 }

Also consider validating DebounceConfig at construction to reject 0ms intervals.


273-276: Don’t ignore send errors; exit tasks when the consumer is gone.

Silently discarding tx.send errors can spin forwarders/flushers after the receiver drops.

Apply this to stop tasks cleanly:

-                for update in to_forward {
-                    let _ = out_tx.send(update).await;
-                }
+                for update in to_forward {
+                    if out_tx.send(update).await.is_err() {
+                        // Receiver dropped; terminate flusher task
+                        return;
+                    }
+                }
-                let _ = params.tx.send(update).await;
+                if params.tx.send(update).await.is_err() {
+                    break; // receiver dropped; end forwarder
+                }
-                let _ = params.tx.send(u).await;
+                if params.tx.send(u).await.is_err() {
+                    break; // receiver dropped; end forwarder
+                }

Also applies to: 366-366, 375-375


219-230: No shutdown path for background tasks.

Pruner, flusher, and recycler loops are infinite and outlive shutdown(), holding resources.

Add a CancellationToken to SubMuxClient and check it in all loops; cancel it from ChainPubsubClient::shutdown().

Also applies to: 232-278, 280-306


728-734: Inconsistent test comment about dedupe window.

Comment says “dedup window is 2s,” but this test sets dedupe_window_millis: Some(100).

Update the comment to reflect the 100ms window to avoid confusion.


446-454: Avoid per-iteration allocation in debounce detection.

Allocating window_slice Vec on each update adds overhead.

Iterate adjacent pairs without allocation:

-                        let start = len - allowed_count;
-                        let window_slice: Vec<Instant> =
-                            arrivals.iter().skip(start).cloned().collect();
-                        window_slice.windows(2).all(|w| {
-                            let dt = w[1].saturating_duration_since(w[0]);
-                            dt <= debounce_interval
-                        })
+                        let start = len - allowed_count;
+                        let mut ok = true;
+                        let mut it = arrivals.iter().skip(start).copied();
+                        if let Some(mut prev) = it.next() {
+                            for cur in it {
+                                if cur.saturating_duration_since(prev) > debounce_interval {
+                                    ok = false; break;
+                                }
+                                prev = cur;
+                            }
+                        }
+                        ok
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)

336-339: Typo in expect message.

“poisonde” -> “poisoned”.

-                .expect("subscription_watchers lock poisonde");
+                .expect("subscription_watchers lock poisoned");
magicblock-chainlink/src/remote_account_provider/mod.rs (1)

156-196: Change impl block specialization to match the actual return type for API clarity

The impl block at line 156 specializes on SubMuxClient<ChainPubsubClientImpl>, but try_from_urls_and_config returns RemoteAccountProvider<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>>. This mismatch is confusing since ChainUpdatesClient (an enum implementing ChainPubsubClient) is what the method actually produces.

Change the impl specialization to SubMuxClient<ChainUpdatesClient> to align with the return type. The type is valid: ChainUpdatesClient implements the required ChainPubsubClient trait.

Verify that call sites in magicblock-chainlink/src/chainlink/mod.rs (line 97) and test-integration/test-chainlink/src/ixtest_context.rs (line 100) still compile and type-infer correctly after the specialization change, as they currently rely on implicit type resolution for the associated function call.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1dfd59 and ba3580b.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
  • test-manual/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (27)
  • Cargo.toml (1 hunks)
  • magicblock-accounts/src/scheduled_commits_processor.rs (2 hunks)
  • magicblock-aperture/src/state/mod.rs (2 hunks)
  • magicblock-api/src/external_config.rs (4 hunks)
  • magicblock-api/src/magic_validator.rs (3 hunks)
  • magicblock-chainlink/Cargo.toml (1 hunks)
  • magicblock-chainlink/src/chainlink/mod.rs (2 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (6 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (5 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/errors.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/mod.rs (8 hunks)
  • magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (1 hunks)
  • magicblock-chainlink/src/submux/debounce_state.rs (1 hunks)
  • magicblock-chainlink/src/submux/mod.rs (18 hunks)
  • magicblock-chainlink/src/testing/chain_pubsub.rs (1 hunks)
  • test-integration/test-chainlink/src/ixtest_context.rs (4 hunks)
  • test-manual/Cargo.toml (1 hunks)
  • test-manual/Makefile (1 hunks)
  • test-manual/README.md (1 hunks)
  • test-manual/helius-laser/Cargo.toml (1 hunks)
  • test-manual/helius-laser/README.md (1 hunks)
  • test-manual/helius-laser/src/main.rs (1 hunks)
  • test-manual/rustfmt-nightly.toml (1 hunks)
  • test-manual/rustfmt.toml (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (9)
magicblock-api/src/external_config.rs (1)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • is_helius_laser_url (100-103)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (3)
  • new_from_url (23-36)
  • shutdown (81-86)
  • subscribe (53-65)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (5)
  • new_from_url (49-56)
  • new (58-87)
  • shutdown (89-99)
  • handle_msg (150-217)
  • add_sub (219-289)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (7)
  • new (174-184)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (7)
  • is_helius_laser_url (100-103)
  • new_from_url (23-36)
  • subscribe (53-65)
  • unsubscribe (67-79)
  • shutdown (81-86)
  • recycle_connections (88-90)
  • take_updates (92-97)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (1)
  • try_new_from_url (44-54)
magicblock-chainlink/src/remote_account_provider/mod.rs (2)
  • subscribe (723-735)
  • unsubscribe (738-749)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (4)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (3)
  • new_from_url (51-74)
  • new (76-99)
  • shutdown (101-104)
magicblock-chainlink/src/remote_account_provider/mod.rs (4)
  • new (135-140)
  • new (222-264)
  • subscribe (723-735)
  • unsubscribe (738-749)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (16)
  • new (174-184)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
  • unsubscribe (24-27)
  • unsubscribe (126-139)
  • unsubscribe (251-259)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • recycle_connections (29-29)
  • recycle_connections (67-97)
  • recycle_connections (228-230)
  • take_updates (31-31)
  • take_updates (99-109)
  • take_updates (232-240)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (5)
  • subscribe (62-71)
  • unsubscribe (73-82)
  • shutdown (84-90)
  • recycle_connections (92-98)
  • take_updates (100-106)
magicblock-api/src/magic_validator.rs (2)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1)
  • new (76-99)
magicblock-chainlink/src/remote_account_provider/mod.rs (2)
  • new (135-140)
  • new (222-264)
magicblock-chainlink/src/submux/mod.rs (2)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • shutdown (81-86)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (3)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
magicblock-chainlink/src/remote_account_provider/mod.rs (5)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1)
  • new (76-99)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • new (58-87)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (1)
  • new (174-184)
magicblock-chainlink/src/submux/mod.rs (1)
  • new (158-169)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1)
  • try_new_from_endpoint (20-57)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • shutdown (81-86)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (4)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • send (190-199)
magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (2)
  • from (43-50)
  • rpc_response (44-44)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (4)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • shutdown (81-86)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • shutdown (89-99)
magicblock-chainlink/src/submux/mod.rs (1)
  • shutdown (547-552)
magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (2)
  • from (43-50)
  • rpc_response (44-44)
🪛 checkmake (0.2.2)
test-manual/Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 markdownlint-cli2 (0.18.1)
test-manual/helius-laser/README.md

28-28: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


33-33: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


38-38: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


43-43: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_format
🔇 Additional comments (33)
test-manual/rustfmt.toml (1)

1-2: LGTM!

Standard Rustfmt configuration that aligns with the project's formatting standards.

magicblock-chainlink/Cargo.toml (1)

11-11: LGTM!

Correctly adds the helius-laserstream workspace dependency to enable Laser GRPC client integration.

test-manual/rustfmt-nightly.toml (1)

1-3: LGTM!

Nightly Rustfmt configuration with appropriate import organization settings. The max_width aligns with the stable configuration.

test-manual/helius-laser/Cargo.toml (1)

1-13: LGTM!

Properly configured package manifest that uses workspace dependencies correctly for the manual test binary.

test-manual/README.md (1)

1-26: LGTM!

Well-structured documentation that clearly explains the manual test setup, requirements, and usage. The rationale for manual testing is well articulated.

magicblock-chainlink/src/testing/chain_pubsub.rs (1)

8-9: All imported types exist in the specified modules.

The rg search confirmed that ChainPubsubActorMessage, SubscriptionUpdate, and ChainPubsubActor are correctly defined in their respective modules. However, cargo check could not complete in the sandbox environment due to Rust toolchain issues.

Please verify locally that imports compile:

cargo check --tests
magicblock-chainlink/src/submux/debounce_state.rs (1)

5-5: Import path update looks correct

The shared pubsub_common::SubscriptionUpdate import aligns with the refactor.

magicblock-chainlink/src/remote_account_provider/errors.rs (1)

32-37: Good extension of error surface; verify propagation paths

Variants look fine. Ensure all laser actor send sites map to ChainLaserActorSendError, and API key validation surfaces MissingApiKey early (constructor/wiring).

Would you like a quick grep script to verify all laser send paths and API-key checks route to these variants?

magicblock-api/src/external_config.rs (1)

4-4: Import looks correct

Importing is_helius_laser_url for GRPC detection is appropriate.

magicblock-accounts/src/scheduled_commits_processor.rs (1)

13-14: Type alias migration LGTM

Swapping ChainPubsubClientImpl → ChainUpdatesClient via SubMuxClient matches the new backend. No issues spotted.

Also applies to: 51-54

magicblock-aperture/src/state/mod.rs (1)

10-11: Consistent wiring to ChainUpdatesClient

Alias and imports updated correctly. Matches the rest of the PR.

Also applies to: 24-27

magicblock-chainlink/src/chainlink/mod.rs (1)

20-22: Return type and imports updated correctly

Type now returns SubMuxClient. Constructor flow remains valid.

Also applies to: 92-93

magicblock-api/src/magic_validator.rs (1)

27-28: Wiring to ChainUpdatesClient and Endpoint::new is correct

Type alias and endpoint construction look good and align with backend selection.

Also applies to: 99-104, 395-397

magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (5)

9-13: Import path adjustments are correct

SubscriptionUpdate/ActorMessage sourced from pubsub_common matches relocations.


28-29: Trait change: shutdown now returns Result

Good API: callers can observe shutdown failures; SubMux already awaits and aggregates.

Please confirm all implementors were updated (Laser, SubMux). CI should catch any missing impls.


59-65: Graceful shutdown path LGTM

Sends Shutdown and awaits ack; propagates errors.


221-223: SubscriptionUpdate::from use is correct

Matches new constructor in pubsub_common, avoids manual struct init.


261-263: Mock shutdown returning Ok(()) is fine

Keeps tests/dev-context simple and compatible with new trait.

magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1)

60-107: Delegation to inner client variants is straightforward

subscribe/unsubscribe/shutdown/recycle/take_updates all forward correctly.

magicblock-chainlink/src/submux/mod.rs (3)

15-16: Imports and type surface alignment look correct.

Using pubsub_common::SubscriptionUpdate and errors::RemoteAccountProviderResult is consistent with the refactor across the R.A.P. surface.


356-357: Correct dedup key uses update.slot.

Switching from rpc_response.context.slot to update.slot matches the new SubscriptionUpdate shape.


635-637: Tests: updates to lamports accessor, slot assertions, and shutdown await all look good.

Please keep CI timeouts generous; several 100ms timeouts can be flaky under load. Consider 2–3x slack where possible.

Also applies to: 641-642, 685-686, 749-750, 811-812, 893-893, 1002-1003, 1040-1040, 1100-1100, 1141-1142, 1186-1187, 1200-1201

magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (2)

176-196: Unsubscribe via drop: verify semantics.

remove_sub drops the per-account stream; create_account_stream doesn’t keep an explicit unsubscribe handle.

Confirm laserstream unsubscribes server‑side when the stream is dropped. If not, carry and call an explicit unsubscribe.

Also applies to: 163-174


198-266: Account update handling looks robust.

Good pubkey consistency check, owner parsing, and construction of SubscriptionUpdate with slot.

magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)

22-36: Client/actor wiring looks sound.

Construction, message passing with oneshots, shutdown, and take_updates mirror existing pubsub client patterns.

Also applies to: 51-98

magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (2)

274-279: Using SubscriptionUpdate::from tuple is correct and clearer.


209-216: Shutdown flow integration looks good.

Gracefully cancels subs and signals via oneshot; worker loop respects cancellation.

Also applies to: 89-99, 127-147

magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (2)

42-51: SubscriptionUpdate::from correctly decodes UiAccount and captures slot.


67-83: Actor message surface looks appropriate.

Includes Shutdown and RecycleConnections responses as Result<()>; consistent with callers.

test-integration/test-chainlink/src/ixtest_context.rs (1)

32-32: Import path change to crate::sleep_ms

Looks fine assuming re-export; otherwise this will fail in tests.

Confirm the symbol is re-exported at crate::sleep_ms.

magicblock-chainlink/src/remote_account_provider/mod.rs (3)

39-41: Module surface updates

Visibility choices look good (actor kept crate-private; clients public).

Also applies to: 44-44, 49-49


54-61: Import consolidation for new updates path

Good alignment with ChainUpdatesClient and SubscriptionUpdate.


291-299: Client construction via ChainUpdatesClient::try_new_from_endpoint

Wiring for Laser vs WebSocket selection is clear; submux over mixed clients is fine.

Also applies to: 303-305

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
magicblock-api/src/external_config.rs (1)

90-101: Panic messages reference wrong variant name

In CustomWithWs arm, two expects mention CustomWithMultipleWs. Fix messages.

-                .expect("rpc url must be set for CustomWithMultipleWs")
+                .expect("rpc url must be set for CustomWithWs")
...
-                .expect("ws urls must be set for CustomWithMultipleWs")
+                .expect("ws urls must be set for CustomWithWs")
magicblock-chainlink/src/submux/mod.rs (1)

502-505: Bug: debounce can enable immediately when detection_window < interval

allowed_in_debounce_window_count returns 0 in that case, causing immediate debouncing on first arrival. Clamp to a safe minimum and require at least one interval (two arrivals).

Apply:

-    fn allowed_in_debounce_window_count(&self) -> usize {
-        (self.debounce_detection_window.as_millis()
-            / self.debounce_interval.as_millis()) as usize
-    }
+    fn allowed_in_debounce_window_count(&self) -> usize {
+        let intervals = (self.debounce_detection_window.as_millis()
+            / self.debounce_interval.as_millis()) as usize;
+        // Require at least 2 arrivals (>=1 interval) to consider enabling debounce.
+        std::cmp::max(2, intervals.saturating_add(1))
+    }

Consider adding a unit test configuring detection_window < interval to assert no immediate debounce.

♻️ Duplicate comments (24)
Cargo.toml (1)

80-80: Use git rev instead of branch for reproducible builds.

The helius-laserstream dependency uses a git branch reference, which can move and reduce build reproducibility. Per the prior review, this should be pinned to a specific commit.

Apply this fix:

-helius-laserstream = { git = "https://github.com/magicblock-labs/laserstream-sdk", branch = "v0.2.2-magicblock" }
+helius-laserstream = { git = "https://github.com/magicblock-labs/laserstream-sdk", rev = "c3e42c5424d317093ce3ce3652d0c9c998f52eba" }
test-manual/Cargo.toml (2)

13-13: Use git rev instead of branch for reproducible builds.

The helius-laserstream dependency uses a git branch reference. This should be pinned to the commit hash for reproducibility, matching the fix needed in the root Cargo.toml.

Apply this fix:

-helius-laserstream = { git = "https://github.com/magicblock-labs/laserstream-sdk", branch = "v0.2.2-magicblock" }
+helius-laserstream = { git = "https://github.com/magicblock-labs/laserstream-sdk", rev = "c3e42c5424d317093ce3ce3652d0c9c998f52eba" }

21-23: Move [[bin]] to package manifest; remove from workspace.

Binary targets cannot be defined in workspace manifests. Cargo only recognizes [patch], [replace], and [profile.*] sections at the workspace level. The [[bin]] section must be moved to helius-laser/Cargo.toml.

Remove this block from test-manual/Cargo.toml and add it to helius-laser/Cargo.toml:

[[bin]]
name = "helius-laser"
path = "src/main.rs"
test-manual/helius-laser/README.md (1)

28-30: Add blank lines around fenced code blocks (MD031).

Fenced code blocks must be surrounded by blank lines for markdown lint compliance. This was flagged in the prior review.

Apply this diff to all code blocks:

  1. Ensure you have a Helius API key set in the `HELIUS_API_KEY` environment variable:
+
     ```bash
     export HELIUS_API_KEY=your_helius_api_key_here
     ```
+
  2. Ensure your Solana CLI is configured for devnet:
+
     ```bash
     solana config set --url devnet
     ```
+
  3. Airdrop some SOL to your configured keypair:
+
     ```bash
     solana airdrop 1
     ```
+
  4. Run the test from the `test-manual` directory:
+
     ```bash
     make manual-test-laser
     ```

Also applies to: 33-35, 38-40, 43-45

test-manual/Makefile (4)

1-8: Declare .PHONY targets to avoid file name collisions.

The fmt, list, and manual-test-laser targets are meta targets that should be declared as .PHONY to prevent conflicts with files of the same name and satisfy checkmake requirements.


26-34: Security: API key exposed in world-readable config file.

The config file /tmp/mb-test-laser.toml contains HELIUS_API_KEY and is created with default permissions (likely 0644), making it readable by all users. Additionally, the file is not removed during cleanup at lines 61-65.


44-46: Infinite wait if validator fails to start.

The loop waits indefinitely for the validator to respond. If startup fails, the Makefile hangs with no diagnostic output or timeout.


49-59: Exit status check is broken: cargo failures not detected.

Each Makefile recipe line runs in a separate shell, so $? at line 53 reflects the previous @echo (line 52), not the cargo run command (lines 49-51). Failures in the laser test will be silently ignored.

test-manual/helius-laser/src/main.rs (5)

9-18: Missing Message import for accurate fee calculation.

The Message type is needed to compute the exact fee for the final transfer transaction (line 175). Without it, the code uses the previous transaction's fee, which may cause the final transfer to fail if the actual fee differs.


81-88: Brittle balance assertions without retry logic.

The immediate assert_eq! checks can fail if the local validator lags behind the remote RPC. A bounded retry loop would reduce flakiness.


166-198: Final transfer uses wrong fee and has unwrap panic risk.

Line 175 uses unwrap() on transaction metadata (panic risk), and line 176 subtracts the previous transaction's fee instead of computing the fee for the upcoming final transfer. This can cause the final transfer to fail if fees differ.


227-261: Remove unnecessary async from synchronous function.

request_account_infos contains no await expressions and should be a plain fn. The .await call at line 136 should also be removed.


274-297: Error handling masks non-404 errors from Helius.

Lines 279-286 treat any Helius error as "account not found" and create a placeholder Account. This can mask network failures, authentication errors, or rate limiting issues.

magicblock-api/src/external_config.rs (4)

102-105: Avoid extra allocation; pass &str and build vector without re-stringifying

Use the existing String; no need for to_string().

-            let is_grpc = is_grpc_url(&ws_url.to_string());
-            let ws_urls =
-                vec![ws_url; if is_grpc { 1 } else { WS_MULTIPLEX_COUNT }];
+            let is_grpc = is_grpc_url(ws_url.as_str());
+            let ws_urls = if is_grpc {
+                vec![ws_url]
+            } else {
+                vec![ws_url.clone(); WS_MULTIPLEX_COUNT]
+            };

108-110: Fix typo in comment: “multple” → “multiple”

Keeps docs clean.

-            // NOTE: we assume that if multple ws urls are provided the user wants
+            // NOTE: we assume that if multiple ws urls are provided the user wants

157-159: Thin wrapper: inline or rename for clarity

is_grpc_url just forwards to is_helius_laser_url; consider inlining or renaming to is_pubsub_grpc_url.


63-85: Port increment can overflow; use checked_add and set only on success

If port is 65535, port + 1 panics in debug or wraps in release. Make it safe.

-                        if let Some(port) = ws_url.port() {
-                            ws_url
-                                .set_port(Some(port + 1))
-                                .expect("valid url with port");
-                        }
+                        if let Some(port) = ws_url.port() {
+                            if let Some(next) = port.checked_add(1) {
+                                ws_url
+                                    .set_port(Some(next))
+                                    .expect("valid url with port");
+                            } // else: skip changing the port on overflow
+                        }
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1)

24-31: Tighten Laser endpoint detection (host/path check, not substring)

Substring matching can false-positive. Parse URL and check host/path.

Proposed change in chain_laser_client.rs:

-pub fn is_helius_laser_url(url: &str) -> bool {
-    // Example: https://laserstream-devnet-ewr.helius-rpc.com
-    url.contains("laserstream") && url.contains("helius-rpc.com")
-}
+pub fn is_helius_laser_url(url: &str) -> bool {
+    if let Ok(parsed) = url::Url::parse(url) {
+        let host = parsed.host_str().unwrap_or_default();
+        let path = parsed.path();
+        (host.ends_with("helius-rpc.com") || host.ends_with(".helius-rpc.com"))
+            && (host.contains("laser") || path.contains("laser"))
+    } else {
+        false
+    }
+}

Remember to add url = "2" in Cargo.toml if not present.

magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)

100-103: Make endpoint detection more robust by parsing the URL.

Substring matching can misclassify URLs. Parse the URL and check the host component.

Apply this diff to use proper URL parsing:

+use url::Url;
+
-pub fn is_helius_laser_url(url: &str) -> bool {
-    // Example: https://laserstream-devnet-ewr.helius-rpc.com
-    url.contains("laserstream") && url.contains("helius-rpc.com")
-}
+pub fn is_helius_laser_url(url: &str) -> bool {
+    Url::parse(url)
+        .ok()
+        .and_then(|u| u.host_str())
+        .map(|host| host.contains("laserstream") && host.ends_with("helius-rpc.com"))
+        .unwrap_or(false)
+}

This ensures detection is based on the hostname, not arbitrary URL components.

magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (2)

40-41: Update stale doc comment.

The comment references [Self::pubsub_client] which doesn't exist in this struct. Update to refer to the Laser client subscription mechanism.

Apply this diff:

-    /// Sends updates for any account subscription that is received via
-    /// the [Self::pubsub_client]
+    /// Sends updates for any account subscription that is received via
+    /// the Laser client subscriptions

47-48: Remove unsafe Send/Sync impls - they are unsound and unnecessary.

The unsafe impl Sync is unsound because StreamMap<Pubkey, LaserStream> contains streams that are only Send, not Sync. Additionally, tokio::spawn only requires Send, not Sync, making these impls unnecessary.

Apply this diff:

-unsafe impl Send for ChainLaserActor {}
-unsafe impl Sync for ChainLaserActor {}

Rely on Rust's auto-traits. If compilation fails, investigate which field blocks Send rather than adding unsafe impls.

test-integration/test-chainlink/src/ixtest_context.rs (1)

284-287: Use expect with context instead of bare unwrap.

In test code, .expect("undelegation_requested failed") provides clearer failure messages than .unwrap().

Apply this diff:

         self.chainlink
             .undelegation_requested(counter_pda)
             .await
-            .unwrap();
+            .expect("undelegation_requested failed");
magicblock-chainlink/src/remote_account_provider/mod.rs (2)

142-153: Make API key extraction robust to query parameter ordering.

The current split_once("?api-key=") fails when api-key is not the first query parameter. Parse the query string properly to handle arbitrary parameter order.

Apply this diff:

     pub fn separate_pubsub_url_and_api_key(&self) -> (String, Option<String>) {
-        let (pubsub_url, pubsub_api_key) = self
+        let (base, query) = self
             .pubsub_url
-            .split_once("?api-key=")
-            .unwrap_or((&self.pubsub_url, ""));
-        let api_key = if !pubsub_api_key.is_empty() {
-            Some(pubsub_api_key.to_string())
-        } else {
-            None
-        };
-        (pubsub_url.to_string(), api_key)
+            .split_once('?')
+            .unwrap_or((self.pubsub_url.as_str(), ""));
+        let api_key = query
+            .split('&')
+            .find_map(|kv| kv.strip_prefix("api-key=").map(|v| v.to_string()));
+        (base.to_string(), api_key)
     }

This handles URLs like wss://host/stream?foo=1&api-key=KEY&bar=2 correctly.


364-377: Clarify error message for missing account in update.

The error message "could not be decoded" is misleading since decoding happens during SubscriptionUpdate construction. The None case here means the account data is missing or decode failed earlier.

Apply this diff to improve clarity:

                     let remote_account = match update.account {
                         Some(account) => RemoteAccount::from_fresh_account(
                             account,
                             slot,
                             RemoteAccountUpdateSource::Subscription,
                         ),
                         None => {
                             error!(
-                                "Account for {} update could not be decoded",
-                                update.pubkey
+                                "Account for {} missing in subscription update at slot {}",
+                                update.pubkey, slot
                             );
                             RemoteAccount::NotFound(slot)
                         }
                     };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1dfd59 and c5bc16e.

⛔ Files ignored due to path filters (3)
  • Cargo.lock is excluded by !**/*.lock
  • test-integration/Cargo.lock is excluded by !**/*.lock
  • test-manual/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (27)
  • Cargo.toml (1 hunks)
  • magicblock-accounts/src/scheduled_commits_processor.rs (2 hunks)
  • magicblock-aperture/src/state/mod.rs (2 hunks)
  • magicblock-api/src/external_config.rs (4 hunks)
  • magicblock-api/src/magic_validator.rs (3 hunks)
  • magicblock-chainlink/Cargo.toml (1 hunks)
  • magicblock-chainlink/src/chainlink/mod.rs (2 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (6 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (5 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/errors.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/mod.rs (8 hunks)
  • magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (1 hunks)
  • magicblock-chainlink/src/submux/debounce_state.rs (1 hunks)
  • magicblock-chainlink/src/submux/mod.rs (18 hunks)
  • magicblock-chainlink/src/testing/chain_pubsub.rs (1 hunks)
  • test-integration/test-chainlink/src/ixtest_context.rs (4 hunks)
  • test-manual/Cargo.toml (1 hunks)
  • test-manual/Makefile (1 hunks)
  • test-manual/README.md (1 hunks)
  • test-manual/helius-laser/Cargo.toml (1 hunks)
  • test-manual/helius-laser/README.md (1 hunks)
  • test-manual/helius-laser/src/main.rs (1 hunks)
  • test-manual/rustfmt-nightly.toml (1 hunks)
  • test-manual/rustfmt.toml (1 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
PR: magicblock-labs/magicblock-validator#578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Applied to files:

  • magicblock-chainlink/src/remote_account_provider/mod.rs
🧬 Code graph analysis (9)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (7)
  • is_helius_laser_url (100-103)
  • new_from_url (23-36)
  • subscribe (53-65)
  • unsubscribe (67-79)
  • shutdown (81-86)
  • recycle_connections (88-90)
  • take_updates (92-97)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (1)
  • try_new_from_url (44-54)
magicblock-chainlink/src/remote_account_provider/mod.rs (2)
  • subscribe (723-735)
  • unsubscribe (738-749)
magicblock-api/src/external_config.rs (1)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • is_helius_laser_url (100-103)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (3)
  • new_from_url (23-36)
  • shutdown (81-86)
  • subscribe (53-65)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (5)
  • new_from_url (49-56)
  • new (58-87)
  • shutdown (89-99)
  • handle_msg (150-217)
  • add_sub (219-289)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (7)
  • new (174-184)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (4)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (2)
  • new_from_url (51-74)
  • new (76-99)
magicblock-chainlink/src/remote_account_provider/mod.rs (3)
  • new (135-140)
  • new (222-264)
  • subscribe (723-735)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (7)
  • new (174-184)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
  • take_updates (31-31)
  • take_updates (99-109)
  • take_updates (232-240)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (2)
  • subscribe (62-71)
  • take_updates (100-106)
magicblock-chainlink/src/remote_account_provider/mod.rs (5)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1)
  • new (76-99)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • new (58-87)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (1)
  • new (174-184)
magicblock-chainlink/src/submux/mod.rs (1)
  • new (158-169)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1)
  • try_new_from_endpoint (20-57)
magicblock-chainlink/src/submux/mod.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • shutdown (81-86)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • shutdown (89-99)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (3)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
magicblock-api/src/magic_validator.rs (1)
magicblock-chainlink/src/remote_account_provider/mod.rs (2)
  • new (135-140)
  • new (222-264)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (4)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • shutdown (81-86)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • shutdown (89-99)
magicblock-chainlink/src/submux/mod.rs (1)
  • shutdown (547-552)
magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (2)
  • from (43-50)
  • rpc_response (44-44)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • shutdown (81-86)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (4)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • send (190-199)
magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (2)
  • from (43-50)
  • rpc_response (44-44)
🪛 checkmake (0.2.2)
test-manual/Makefile

[warning] 1-1: Missing required phony target "all"

(minphony)


[warning] 1-1: Missing required phony target "clean"

(minphony)


[warning] 1-1: Missing required phony target "test"

(minphony)

🪛 markdownlint-cli2 (0.18.1)
test-manual/helius-laser/README.md

28-28: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


33-33: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


38-38: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)


43-43: Fenced code blocks should be surrounded by blank lines

(MD031, blanks-around-fences)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
🔇 Additional comments (51)
test-manual/rustfmt.toml (1)

1-2: Configuration looks good.

Standard rustfmt settings appropriate for the test-manual workspace. This complements the nightly-specific configuration.

test-manual/rustfmt-nightly.toml (1)

1-3: Configuration is valid.

Nightly-specific settings for import organization are appropriate. Complements the standard rustfmt.toml.

magicblock-chainlink/Cargo.toml (1)

11-11: Dependency reference is correct.

The helius-laserstream dependency correctly references the workspace definition. However, ensure the root Cargo.toml dependency is fixed for reproducible builds (see notes on root Cargo.toml).

test-manual/helius-laser/Cargo.toml (1)

1-13: Package manifest is correct.

The helius-laser package manifest is well-formed. Note that it will need a [[bin]] section added (to be moved from test-manual/Cargo.toml):

[[bin]]
name = "helius-laser"
path = "src/main.rs"
test-manual/README.md (1)

1-26: Documentation is clear and well-structured.

Provides good overview of manual test purpose and requirements. Cross-references to helius-laser/README.md for detailed instructions are appropriate.

magicblock-chainlink/src/submux/debounce_state.rs (1)

5-5: Import path update is correct

Matches the pubsub_common relocation. No issues.

magicblock-chainlink/src/remote_account_provider/errors.rs (1)

32-37: New error variants verified as safe; no match arm updates required

Verification confirms the additions are sound:

  • MissingApiKey(String) correctly passes endpoint identifier ("Helius laser endpoint: {endpoint.pubsub_url}"), not the actual key
  • ChainLaserActorSendError(String, String) passes error descriptions (err.to_string() and debug format), no secrets
  • No exhaustive match statements on RemoteAccountProviderError in the codebase require updating
magicblock-accounts/src/scheduled_commits_processor.rs (1)

13-14: ChainUpdatesClient migration verified

The import swap (lines 13–14) and type alias change (lines 51–54) are correct. Provider wiring verified: ChainUpdatesClient::try_new_from_endpoint is correctly called with Endpoint and CommitmentConfig for each endpoint, properly routing to WebSocket or Laser variants.

magicblock-aperture/src/state/mod.rs (1)

10-11: Migration verified: ChainUpdatesClient successfully replaces ChainPubsubClientImpl in aperture

No remaining SubMuxClient<ChainPubsubClientImpl> aliases found in magicblock-aperture. The crate now consistently uses SubMuxClient<ChainUpdatesClient> (line 24). Remaining ChainPubsubClientImpl references are confined to the separate magicblock-chainlink crate as internal implementation details and are not part of the aperture public interface.

magicblock-api/src/magic_validator.rs (3)

27-31: Import swap to ChainUpdatesClient looks correct

Migration to chain_updates_client::ChainUpdatesClient aligns with the new multiplexed client. No issues spotted.


99-104: Type alias updated to SubMuxClient

Alias matches the new Chainlink generic signature elsewhere. Looks good.


395-397: Endpoint construction change: confirm mixed backends in ws_urls

Using Endpoint::new(rpc_url, pubsub_url) is fine. Please confirm remote_cluster.ws_urls may include both WebSocket and Laser URLs (incl. API keys) so ChainUpdatesClient can branch per endpoint at runtime. If Laser endpoints live elsewhere, wire them in here too.

magicblock-chainlink/src/testing/chain_pubsub.rs (1)

8-10: Test imports updated to pubsub_common

Import path changes are consistent with the refactor. All good.

magicblock-chainlink/src/chainlink/mod.rs (2)

20-22: Import surface updated to ChainUpdatesClient

Matches new remote_account_provider surface. No concerns.


92-93: Public return type switched to SubMuxClient

Signature aligns with new client. OK.

magicblock-chainlink/src/submux/mod.rs (4)

13-16: SubscriptionUpdate import path change

Using remote_account_provider::pubsub_common::SubscriptionUpdate is consistent with the refactor.


349-357: Dedup keyed by (pubkey, slot) is appropriate

Switching to update.slot for dedup is correct given the new SubscriptionUpdate shape.


547-552: Shutdown now returns Result; propagate and consider timeouts

Awaiting inner client shutdown and bubbling errors is good. Add a bounded timeout to avoid indefinite hangs if an actor is stuck.

If desired, we can add a wrapper:

pub async fn shutdown_with_timeout<T: ChainPubsubClient>(
    client: &T,
    dur: std::time::Duration,
) -> RemoteAccountProviderResult<()> {
    match tokio::time::timeout(dur, client.shutdown()).await {
        Ok(r) => r,
        Err(_) => Err(crate::remote_account_provider::errors::RemoteAccountProviderError::ShutdownTimeout),
    }
}

635-642: Tests updated for new update shape and shutdown

Accessing lamports via update.account and slot via update.slot, plus awaiting shutdown, all align with API changes. Looks good.

Also applies to: 726-750, 797-811, 871-893, 1002-1040, 1099-1142, 1186-1201

magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1)

13-17: Wrapper and delegation look correct

Enum wrapper and ChainPubsubClient delegation are straightforward. No issues.

Also applies to: 60-107

magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (5)

10-12: LGTM! Import reorganization aligns with the new module structure.

The imports correctly reference the relocated types from pubsub_common.


28-28: LGTM! Appropriate error handling added to shutdown.

The updated signature enables proper error propagation from the actor shutdown flow.


59-65: LGTM! Shutdown implementation correctly uses actor messaging pattern.

The oneshot channel pattern ensures the caller waits for shutdown acknowledgement from the actor.


221-222: LGTM! Using From trait for cleaner construction.

The change to use SubscriptionUpdate::from((pubkey, rpc_response)) aligns with the centralized type definitions in pubsub_common.


261-263: LGTM! Mock shutdown signature updated consistently.

The mock correctly implements the updated trait signature.

magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (5)

22-36: Actor task not tracked; consider error handling.

The tokio::spawn(actor.run()) at line 34 is fire-and-forget. If the actor panics or terminates unexpectedly, there's no way to detect it. Consider either:

  • Storing the JoinHandle for debugging/monitoring purposes, or
  • Adding error logging within the actor's run method

This is acceptable for now but may complicate diagnostics in production.


38-48: LGTM! Error mapping provides good diagnostics.

The helper correctly maps channel send errors to the domain-specific ChainLaserActorSendError variant with both display and debug information.


53-79: LGTM! Subscribe/unsubscribe follow consistent actor messaging pattern.

Both methods correctly use oneshot channels for synchronous request-response communication with the actor.


81-90: LGTM! Shutdown and recycle implementations are appropriate.

The no-op recycle_connections with trace logging is suitable for Laserstream's persistent connection model.


92-97: LGTM! take_updates correctly prevents double-take with clear panic message.

The implementation matches the WebSocket client and appropriately panics on double-take to surface logic bugs early.

magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (6)

50-99: LGTM! Constructors follow consistent pattern with WebSocket actor.

The separation of new_from_url (convenience) and new (flexible) is well-structured, and channel sizing is appropriately centralized.


106-120: LGTM! Actor run loop is clean and well-structured.

The use of tokio::select! with conditional stream polling (if !self.subscriptions.is_empty()) prevents busy-waiting when no subscriptions are active.


122-145: LGTM! Message handling covers all cases appropriately.

The no-op for RecycleConnections aligns with Laserstream's persistent connection model, and shutdown response handling gracefully logs failures instead of panicking.


147-174: LGTM! Subscription management is defensive and well-logged.

The warning on duplicate subscriptions (line 154) and graceful error handling with unwrap_or_else are good practices for debugging without crashing the actor.


176-195: LGTM! Per-account stream creation follows Laserstream API.

The pattern of creating individual streams for each account enables independent subscription management and cancellation.


197-265: LGTM! Excellent defensive validation and error handling.

The defensive pubkey check (lines 213-224) prevents stream cross-contamination, and the comment at lines 204-207 clearly explains the expected behavior when accounts are closed. Error handling is consistent and non-fatal throughout.

magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (4)

7-7: LGTM! Import reorganization aligns with shared type centralization.

The imports correctly reference the relocated types from pubsub_common module.

Also applies to: 10-10, 17-20


89-98: LGTM! Shutdown refactor improves separation of concerns.

Converting shutdown to a standalone function with explicit parameters makes the actor's shutdown semantics clearer and enables better testing.


131-131: LGTM! Shutdown handling integrated consistently.

Threading the shutdown_token through handle_msg enables coordinated shutdown, and the new Shutdown branch correctly invokes the refactored shutdown function.

Also applies to: 152-152, 209-215


274-277: LGTM! Using From trait for consistent update construction.

The change aligns with the centralized SubscriptionUpdate type in pubsub_common and its From trait implementation.

magicblock-chainlink/src/remote_account_provider/pubsub_common.rs (5)

13-29: LGTM! Clean configuration struct with convenience constructor.

The from_url constructor provides good ergonomics for the common case.


31-61: LGTM! Well-designed type with helpful trait implementations.

The From implementation gracefully handles decode failures by setting account to None, and the Display impl provides useful debugging output.


63-65: LGTM! Minimal wrapper type for subscription tracking.

Encapsulating the CancellationToken in a named struct improves code clarity.


67-83: LGTM! Clean actor message enum with consistent response pattern.

All variants include oneshot response channels for synchronous request-response semantics, which is the correct pattern for actor communication.


85-86: LGTM! Centralized channel size constants.

The buffer sizes (5,000 for updates, 1,000 for messages) are reasonable for high-throughput scenarios and centralizing them ensures consistency across actors.

test-integration/test-chainlink/src/ixtest_context.rs (3)

54-55: LGTM! New public fields improve test ergonomics.

Exposing cloner and validator_kp in the test context reduces boilerplate in individual tests.


351-351: LGTM! Underscore prefix correctly indicates intentionally unused value.

Renaming to _sig follows Rust conventions and suppresses unused variable warnings appropriately.


13-14: Verification confirms: Type migration to ChainUpdatesClient is complete within ixtest_context.rs, but 4 other files still contain the old type.

The search results show remaining uses of SubMuxClient<ChainPubsubClientImpl> in:

  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs (lines 26, 35)
  • magicblock-chainlink/src/remote_account_provider/mod.rs (lines 159, 952)

Whether these require updates as part of this PR is unclear. Confirm whether these files are in scope for this change or if they're being addressed separately.

magicblock-chainlink/src/remote_account_provider/mod.rs (3)

39-49: LGTM! New module declarations follow appropriate visibility patterns.

The laser-specific modules and pubsub_common are correctly exposed as public, while chain_laser_actor remains internal.


54-61: LGTM! Import updates align with type centralization.

The imports correctly reference the new ChainUpdatesClient enum and centralized SubscriptionUpdate type.


171-171: LGTM! Type migration to ChainUpdatesClient is complete and consistent.

The changes correctly update all type parameters and construction calls to use the new multiplexed ChainUpdatesClient type.

Also applies to: 183-183, 274-274, 292-298

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
magicblock-chainlink/src/remote_account_provider/mod.rs (1)

156-173: Fix impl specialization mismatch for factory helper

The impl block at lines 156-173 is specialized for SubMuxClient<ChainPubsubClientImpl>, but the method try_from_urls_and_config returns RemoteAccountProvider<..., SubMuxClient<ChainUpdatesClient>>. ChainUpdatesClient is a distinct enum type that implements ChainPubsubClient, not the same as ChainPubsubClientImpl. This mismatch creates confusion about which impl block applies and risks method resolution issues at call sites.

Change the impl specialization to match the actual return type:

-impl
-    RemoteAccountProvider<
-        ChainRpcClientImpl,
-        SubMuxClient<ChainPubsubClientImpl>,
-    >
-{
+impl
+    RemoteAccountProvider<
+        ChainRpcClientImpl,
+        SubMuxClient<ChainUpdatesClient>,
+    >
+{
     pub async fn try_from_urls_and_config(
         endpoints: &[Endpoint],
         commitment: CommitmentConfig,
         subscription_forwarder: mpsc::Sender<ForwardedSubscriptionUpdate>,
         config: &RemoteAccountProviderConfig,
     ) -> ChainlinkResult<
         Option<
             RemoteAccountProvider<
                 ChainRpcClientImpl,
                 SubMuxClient<ChainUpdatesClient>,
             >,
         >,
     > {
         // unchanged
     }
 }

The call site at src/chainlink/mod.rs:97 relies on return-type inference, so it will automatically benefit from the corrected impl.

♻️ Duplicate comments (1)
magicblock-chainlink/src/remote_account_provider/mod.rs (1)

365-377: Clarify log when update.account is None (no decoding step anymore)

Message “could not be decoded” is misleading now that we no longer decode RPC values. Prefer an explicit “missing account in subscription update”.

-                        None => {
-                            error!(
-                                "Account for {} update could not be decoded",
-                                update.pubkey
-                            );
-                            RemoteAccount::NotFound(slot)
-                        }
+                        None => {
+                            warn!(
+                                "Account for {} missing in subscription update at slot {} (treating as NotFound)",
+                                update.pubkey, slot
+                            );
+                            RemoteAccount::NotFound(slot)
+                        }

As per previous review guidance. [Based on learnings]

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5bc16e and c76a66d.

📒 Files selected for processing (5)
  • magicblock-chainlink/src/remote_account_provider/mod.rs (9 hunks)
  • magicblock-chainlink/src/testing/chain_pubsub.rs (2 hunks)
  • test-integration/test-chainlink/tests/chain_pubsub_actor.rs (3 hunks)
  • test-integration/test-chainlink/tests/chain_pubsub_client.rs (3 hunks)
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs (3 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-26T16:53:29.771Z
Learnt from: thlorenz
PR: magicblock-labs/magicblock-validator#587
File: magicblock-chainlink/src/remote_account_provider/mod.rs:134-0
Timestamp: 2025-10-26T16:53:29.771Z
Learning: In magicblock-chainlink/src/remote_account_provider/mod.rs, the `Endpoint::separate_pubsub_url_and_api_key()` method uses `split_once("?api-key=")` because the api-key parameter is always the only query parameter right after `?`. No additional query parameter parsing is needed for this use case.

Applied to files:

  • magicblock-chainlink/src/remote_account_provider/mod.rs
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
PR: magicblock-labs/magicblock-validator#578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Applied to files:

  • magicblock-chainlink/src/remote_account_provider/mod.rs
🧬 Code graph analysis (3)
magicblock-chainlink/src/testing/chain_pubsub.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (3)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • shutdown (89-99)
magicblock-chainlink/src/submux/mod.rs (1)
  • shutdown (547-552)
test-integration/test-chainlink/tests/chain_pubsub_actor.rs (1)
magicblock-chainlink/src/testing/chain_pubsub.rs (1)
  • shutdown (68-77)
magicblock-chainlink/src/remote_account_provider/mod.rs (5)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1)
  • new (76-99)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (1)
  • new (174-184)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • new (58-87)
magicblock-chainlink/src/submux/mod.rs (1)
  • new (158-169)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1)
  • try_new_from_endpoint (20-57)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_format
🔇 Additional comments (7)
magicblock-chainlink/src/testing/chain_pubsub.rs (2)

8-9: LGTM! Clean refactoring of imports.

The import paths have been updated to reflect the centralization of pub/sub types into pubsub_common. This improves code organization without affecting functionality.


68-77: LGTM! Well-implemented test helper.

The new shutdown helper function follows the exact same pattern as the existing test helpers (subscribe, unsubscribe, recycle), ensuring consistency and maintainability. The implementation correctly uses a oneshot channel for acknowledgement and provides clear error messages.

test-integration/test-chainlink/tests/chain_pubsub_actor.rs (1)

2-2: LGTM: updated imports and public shutdown helper usage are consistent

Importing SubscriptionUpdate from pubsub_common and using testing::chain_pubsub::shutdown matches the new API. No issues spotted.

Also applies to: 5-6, 105-106, 165-166

test-integration/test-chainlink/tests/chain_pubsub_client.rs (1)

100-106: LGTM: clock deserialization and slot equality

Reading Clock from account.data and asserting update.slot == clock.slot aligns with the production optimization.

magicblock-chainlink/src/remote_account_provider/mod.rs (3)

39-50: LGTM: module structure updates

Adding chain_laser_* and chain_updates_client along with pubsub_common export matches the new backend split.


54-61: LGTM: internal uses updated

Switch to ChainUpdatesClient and pubsub_common::SubscriptionUpdate is consistent across the file.


134-154: LGTM: Endpoint helpers (document constraint)

Endpoint::new and the simple api-key splitter are fine given the invariant that api-key is the only query param immediately after '?'. Consider adding a doc comment to encode this assumption.

“Based on learnings”

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
test-manual/helius-laser/src/main.rs (1)

263-300: Remove unnecessary async from compare_account_states.

The function is declared async but contains no await calls, adding unnecessary overhead.

Apply this diff:

-async fn compare_account_states(
+fn compare_account_states(
     helius_client: &RpcClient,
     local_client: &RpcClient,
     pubkey: &solana_sdk::pubkey::Pubkey,
     account_name: &str,
 ) -> Result<()> {

And remove .await from the call sites:

     compare_account_states(
         &remote_rpc_client,
         &local_rpc_client,
         &from_pubkey,
         "from",
     )
-    .await?;
+    ?;
     compare_account_states(
         &remote_rpc_client,
         &local_rpc_client,
         &to_pubkey,
         "to",
     )
-    .await?;
+    ?;
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c76a66d and 6cf4f72.

📒 Files selected for processing (4)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1 hunks)
  • magicblock-chainlink/src/remote_account_provider/mod.rs (10 hunks)
  • test-manual/Makefile (1 hunks)
  • test-manual/helius-laser/src/main.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📓 Common learnings
Learnt from: thlorenz
PR: magicblock-labs/magicblock-validator#587
File: test-manual/Cargo.toml:0-0
Timestamp: 2025-10-26T16:54:39.084Z
Learning: In the magicblock-validator repository, use git branch references (not commit hashes or tags) for the helius-laserstream dependency to allow automatic updates when the branch is pushed to.
📚 Learning: 2025-10-26T16:53:29.820Z
Learnt from: thlorenz
PR: magicblock-labs/magicblock-validator#587
File: magicblock-chainlink/src/remote_account_provider/mod.rs:134-0
Timestamp: 2025-10-26T16:53:29.820Z
Learning: In magicblock-chainlink/src/remote_account_provider/mod.rs, the `Endpoint::separate_pubsub_url_and_api_key()` method uses `split_once("?api-key=")` because the api-key parameter is always the only query parameter right after `?`. No additional query parameter parsing is needed for this use case.

Applied to files:

  • magicblock-chainlink/src/remote_account_provider/mod.rs
📚 Learning: 2025-10-21T14:00:54.642Z
Learnt from: bmuddha
PR: magicblock-labs/magicblock-validator#578
File: magicblock-aperture/src/requests/websocket/account_subscribe.rs:18-27
Timestamp: 2025-10-21T14:00:54.642Z
Learning: In magicblock-aperture account_subscribe handler (src/requests/websocket/account_subscribe.rs), the RpcAccountInfoConfig fields data_slice, commitment, and min_context_slot are currently ignored—only encoding is applied. This is tracked as technical debt in issue #579: https://github.com/magicblock-labs/magicblock-validator/issues/579

Applied to files:

  • magicblock-chainlink/src/remote_account_provider/mod.rs
📚 Learning: 2025-10-27T09:55:17.782Z
Learnt from: thlorenz
PR: magicblock-labs/magicblock-validator#587
File: magicblock-chainlink/src/remote_account_provider/mod.rs:296-298
Timestamp: 2025-10-27T09:55:17.782Z
Learning: In the magicblock-validator codebase, it is acceptable to log API keys in debug/info statements because logs are private and the team considers API keys not that sensitive in their security model.

Applied to files:

  • magicblock-chainlink/src/remote_account_provider/mod.rs
🧬 Code graph analysis (2)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (5)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (3)
  • new_from_url (23-36)
  • shutdown (81-86)
  • subscribe (53-65)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (5)
  • new_from_url (49-56)
  • new (58-87)
  • shutdown (89-99)
  • handle_msg (150-217)
  • add_sub (219-289)
magicblock-chainlink/src/remote_account_provider/mod.rs (4)
  • default (120-126)
  • new (136-141)
  • new (223-265)
  • subscribe (721-733)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (7)
  • new (174-184)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (2)
  • shutdown (84-90)
  • subscribe (62-71)
magicblock-chainlink/src/remote_account_provider/mod.rs (4)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1)
  • new (73-96)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (1)
  • new (58-87)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (1)
  • new (174-184)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (1)
  • try_new_from_endpoint (20-57)
🪛 checkmake (0.2.2)
test-manual/Makefile

[warning] 66-66: Missing required phony target "all"

(minphony)


[warning] 66-66: Missing required phony target "clean"

(minphony)


[warning] 66-66: Missing required phony target "test"

(minphony)

🪛 GitHub Actions: Run CI - Format
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs

[error] 192-198: rustfmt check failed. Function signature formatting inconsistency detected by cargo +nightly fmt. Please run 'cargo +nightly fmt -- --config-path rustfmt-nightly.toml' to fix formatting in this file.


[error] Diff indicates a formatting change is needed for handle_account_update signature.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
🔇 Additional comments (13)
magicblock-chainlink/src/remote_account_provider/mod.rs (6)

19-19: LGTM! Module structure supports unified pubsub abstraction.

The new modules (chain_laser_actor, chain_laser_client, chain_updates_client, pubsub_common) and updated imports properly establish the infrastructure for supporting both WebSocket and Laser gRPC clients through a unified interface. The futures_util::future import enables parallel client initialization.

Also applies to: 40-50, 55-62


135-155: LGTM! Endpoint helpers are appropriate.

The new() constructor and separate_pubsub_url_and_api_key() method provide clean API key extraction from Helius URLs. Based on learnings, the split_once("?api-key=") approach is acceptable since the api-key parameter is always the only query parameter in your use case.


172-172: LGTM! Type signature updates are consistent.

All function signatures correctly updated from SubMuxClient<ChainPubsubClientImpl> to SubMuxClient<ChainUpdatesClient>, maintaining consistency throughout the refactoring. The new ChainUpdatesClient enum properly unifies WebSocket and Laser client handling.

Also applies to: 184-184, 275-275, 302-302, 960-960


293-297: LGTM! Parallel client initialization improves startup time.

The use of future::try_join_all() properly parallelizes endpoint initialization, reducing startup time when multiple endpoints are configured. Error handling is preserved through the try_join_all semantics (short-circuits on first error), and results are correctly mapped to Arc-wrapped clients.


346-346: LGTM! Update handling correctly adapted to unified SubscriptionUpdate.

The changes properly reflect the simplified SubscriptionUpdate structure:

  • Direct access to update.slot (line 346) instead of nested rpc_response.context.slot
  • Direct access to update.account (lines 362-375) instead of decoding rpc_response.value

The error message "could not be decoded" appropriately covers both client types: WebSocket decode failures from UiAccount and missing account data from Laser streams.

Also applies to: 362-375


959-966: LGTM! Test accessor maintains testing infrastructure.

The new rpc_client() accessor for RemoteAccountProvider<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>> properly maintains test infrastructure after the type parameter changes. It follows the existing pattern established for other type combinations and is correctly cfg-gated.

magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (7)

1-28: LGTM: Imports and type aliases are well-structured.

The imports are appropriate for async stream handling with Helius Laserstream, and the type aliases improve code readability. The LaserStream type correctly requires only Send (not Sync) for use with tokio::spawn.


33-45: LGTM: Struct definition is correct and past issues resolved.

The doc comment now correctly describes the subscription mechanism (previously flagged stale reference has been fixed), and the unsafe Send/Sync impls have been properly removed (relying on auto-traits).


103-117: LGTM: Event loop correctly implements the actor pattern.

The tokio::select! with the guard condition on line 112 efficiently handles messages and stream updates, preventing unnecessary polling when the subscription map is empty.


119-142: LGTM: Message handling is correct.

The no-op for RecycleConnections (line 130-132) is appropriate since Laserstream gRPC doesn't require connection recycling like WebSocket-based pubsub. Error handling properly logs failures without panicking.


160-171: LGTM: Unsubscribe logic is correct.

The method cleanly removes the subscription and handles response send failures appropriately.


195-262: LGTM: Account update handling is robust.

The defensive pubkey validation (lines 210-221), comprehensive error handling, and the reference to verification testing (lines 201-204) demonstrate thorough implementation. The error paths properly log without panicking.


268-277: LGTM: Commitment level conversion is correct.

The exhaustive match ensures compile-time safety if commitment variants change.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
magicblock-api/src/external_config.rs (1)

102-102: Remove unnecessary String allocation.

The ws_url is already a String, so calling .to_string() creates an unnecessary allocation.

Apply this diff:

-            let is_grpc = is_grpc_url(&ws_url.to_string());
+            let is_grpc = is_grpc_url(&ws_url);
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (2)

144-158: Avoid creating a stream when already subscribed.

Create the stream only after confirming the key isn’t present to prevent wasted connections/allocations.

     ) {
-        let stream = self.create_account_stream(pubkey);
         if self.subscriptions.contains_key(&pubkey) {
             warn!("Already subscribed to account {}", pubkey);
         } else {
+            let stream = self.create_account_stream(pubkey);
             self.subscriptions.insert(pubkey, Box::pin(stream));
         }
         sub_response.send(Ok(())).unwrap_or_else(|_| {
             warn!("Failed to send subscribe response for account {}", pubkey)
         });
     }

47-71: Expose connection parameters via config (already noted).

Making timeouts/keepalives/retry counts configurable would help tune reliability across envs.

Also applies to: 73-96

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6cf4f72 and c763599.

📒 Files selected for processing (4)
  • magicblock-api/src/external_config.rs (4 hunks)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1 hunks)
  • test-integration/test-chainlink/tests/chain_pubsub_client.rs (3 hunks)
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
magicblock-api/src/external_config.rs (1)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (1)
  • is_helius_laser_url (100-103)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (3)
  • new_from_url (23-36)
  • shutdown (81-86)
  • subscribe (53-65)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (7)
  • new (174-184)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
magicblock-chainlink/src/remote_account_provider/chain_updates_client.rs (2)
  • shutdown (84-90)
  • subscribe (62-71)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
🔇 Additional comments (8)
test-integration/test-chainlink/tests/ix_remote_account_provider.rs (1)

6-6: LGTM! Clean migration to ChainUpdatesClient.

The migration from ChainPubsubClientImpl to ChainUpdatesClient is consistent across all usage sites in this test file. The type parameters, function signatures, and instantiations all correctly reflect the new abstraction.

Also applies to: 24-34

test-integration/test-chainlink/tests/chain_pubsub_client.rs (3)

9-9: LGTM! Import reflects module reorganization.

The import path update to pubsub_common::SubscriptionUpdate aligns with the PR's introduction of shared pubsub types in the pubsub_common module.


39-39: LGTM! Clean pattern matching for optional account.

The use of map_or(0, |acc| acc.lamports) cleanly handles the case when account is None, returning 0 as a sensible default for lamports. This reflects the structural change from rpc_response.value to the account field.


92-92: LGTM! Clock test correctly updated for new data structure.

The test has been properly migrated to use the new SubscriptionUpdate structure:

  • Clock data is now extracted from update.account.data instead of rpc_response.value
  • The assertion at Line 103 validates that update.slot matches clock_value.slot, which is a useful invariant

The ignored shutdown result at Line 92 was previously discussed and intentionally left as-is for test simplicity.

Also applies to: 98-103

magicblock-api/src/external_config.rs (3)

4-4: LGTM!

The import is necessary for gRPC endpoint detection and properly scoped.


63-86: LGTM!

The conditional logic correctly detects gRPC endpoints and bypasses WebSocket-specific multiplexing, scheme adjustment, and port increment. The use of as_ref() on line 67 avoids unnecessary allocation.


157-159: LGTM!

The abstraction layer is reasonable and provides flexibility for future extensions to gRPC detection logic.

magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1)

173-192: Add documentation and explicit Send trait bound to improve signature clarity.

The proposed changes are valid:

  • The web search confirms that dropping the stream automatically closes the server-side subscription—no separate handle retention needed.
  • The codebase already defines type LaserStream = Pin<Box<dyn Stream<Item = LaserResult> + Send>> (line 27), and the stream from create_account_stream is stored in subscriptions: StreamMap<Pubkey, LaserStream>, which requires Send. Adding + Send to the return type makes this contract explicit at the function signature rather than relying on implicit conversion.
  • All three documentation additions clarify intent without affecting behavior.
-    ) -> impl Stream<Item = LaserResult> {
+    ) -> impl Stream<Item = LaserResult> + Send {
         let mut accounts = HashMap::new();
         accounts.insert(
-            "account_subs".into(),
+            // Arbitrary local label to group this filter; not meaningful to the API.
+            "account_subs".into(),
             SubscribeRequestFilterAccounts {
                 account: vec![pubkey.to_string()],
                 ..Default::default()
             },
         );
         let request = SubscribeRequest {
             accounts,
             commitment: Some(self.commitment.into()),
             ..Default::default()
         };
-        client::subscribe(self.laser_client_config.clone(), request).0
+        // client::subscribe returns (stream, meta/unsub); we only need the stream here.
+        client::subscribe(self.laser_client_config.clone(), request).0
     }

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c763599 and 56215a1.

📒 Files selected for processing (2)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1 hunks)
  • test-integration/test-chainlink/tests/chain_pubsub_client.rs (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (3)
  • new_from_url (23-36)
  • shutdown (81-86)
  • subscribe (53-65)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (3)
  • new_from_url (49-56)
  • new (58-87)
  • shutdown (89-99)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (7)
  • new (174-184)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_lint
🔇 Additional comments (9)
test-integration/test-chainlink/tests/chain_pubsub_client.rs (3)

9-9: LGTM! Import path updated for pubsub_common refactoring.

The import path correctly reflects the move of SubscriptionUpdate to the pubsub_common module, aligning with the broader type consolidation in this PR.


39-39: LGTM! Simplified mapping improves readability.

The map_or refactoring successfully addresses the previous review feedback and provides a cleaner, more idiomatic implementation.


98-103: LGTM! Well-documented test validates important optimization.

The test correctly verifies that update.slot matches clock_value.slot, and the inline comment provides valuable documentation explaining why production code can use update.slot directly instead of parsing clock data. This is excellent test-driven documentation of a performance optimization.

magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (6)

1-28: LGTM: Clean imports and well-defined type aliases.

The imports are well-organized and the type aliases (LaserResult, LaserStreamUpdate, LaserStream) improve code readability throughout the module.


33-45: LGTM: Well-structured actor with appropriate fields.

The struct correctly models an actor that manages per-account gRPC subscriptions. The use of StreamMap for multiplexing multiple account streams is appropriate.


47-96: LGTM: Constructors follow actor pattern correctly.

The two-tier constructor pattern (convenience new_from_url and explicit new) provides good ergonomics. Channel setup and initialization are correct.


103-131: LGTM: Run loop correctly handles channel closure and stream updates.

The select! loop properly handles both message reception and subscription updates, with correct None handling for graceful shutdown (addressed from previous review).


174-206: LGTM: Subscription removal and stream creation are correct.

The remove_sub method correctly removes subscriptions and always sends a response. The create_account_stream helper properly constructs a per-account subscription request with the configured commitment level.


208-294: LGTM: Robust update handling with comprehensive error checks.

The handle_account_update method includes thorough validation (pubkey mismatch check, owner parsing) and detailed error logging. The comment referencing the gist about closed accounts is helpful context. The grpc_commitment_from_solana helper is straightforward and correct.

Note: Failed subscriptions continue logging errors without being removed, which allows recovery from transient failures but may produce repeated error logs for persistent issues. This appears intentional for resilience.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 56215a1 and 3cf8f13.

📒 Files selected for processing (1)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (3)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (3)
  • new_from_url (23-36)
  • shutdown (81-86)
  • subscribe (53-65)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (5)
  • new_from_url (49-56)
  • new (58-87)
  • shutdown (89-99)
  • handle_msg (150-217)
  • add_sub (219-289)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_client.rs (7)
  • new (174-184)
  • shutdown (28-28)
  • shutdown (59-65)
  • shutdown (261-263)
  • subscribe (20-23)
  • subscribe (111-124)
  • subscribe (241-249)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3cf8f13 and be27ee7.

📒 Files selected for processing (1)
  • magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (2)
magicblock-chainlink/src/remote_account_provider/chain_laser_client.rs (3)
  • new_from_url (23-36)
  • shutdown (81-86)
  • subscribe (53-65)
magicblock-chainlink/src/remote_account_provider/chain_pubsub_actor.rs (5)
  • new_from_url (49-56)
  • new (58-87)
  • shutdown (89-99)
  • handle_msg (150-217)
  • add_sub (219-289)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: run_make_ci_format
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_lint
🔇 Additional comments (1)
magicblock-chainlink/src/remote_account_provider/chain_laser_actor.rs (1)

300-305: No changes needed. The code correctly follows LaserStream's recommended error-handling pattern.

LaserStream has built-in automatic reconnection with configurable retry behavior and backoff, and the recommended client behavior is to log errors by relying on the SDK's reconnect. Your code at lines 300-305 does exactly this: it logs the error and lets the SDK handle recovery. The concern about repeated error logs is mitigated by the SDK's backoff behavior. Additionally, when a stream permanently fails (returns None), the StreamMap will automatically remove it on the next poll cycle.

Comment on lines +216 to +235
/// Helper to create a dedicated stream for a single account.
fn create_account_stream(
&self,
pubkey: Pubkey,
) -> impl Stream<Item = LaserResult> {
let mut accounts = HashMap::new();
accounts.insert(
"account_subs".into(),
SubscribeRequestFilterAccounts {
account: vec![pubkey.to_string()],
..Default::default()
},
);
let request = SubscribeRequest {
accounts,
commitment: Some(self.commitment.into()),
..Default::default()
};
client::subscribe(self.laser_client_config.clone(), request).0
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider the performance impact of cloning laser_client_config per subscription.

The client::subscribe call clones the entire LaserstreamConfig (including API key, endpoint URL, and channel options) for each account subscription. While this is likely required by the helius-laserstream API's ownership model, it could have performance implications with many subscriptions.

If the helius-laserstream library supports connection pooling or shared client instances, consider refactoring to reuse a single client or config reference. Otherwise, this is acceptable as-is given API constraints.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be27ee7 and c0741de.

📒 Files selected for processing (2)
  • magicblock-chainlink/src/chainlink/mod.rs (2 hunks)
  • test-integration/test-chainlink/tests/ix_remote_account_provider.rs (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: run_make_ci_lint
  • GitHub Check: run_make_ci_test
  • GitHub Check: run_make_ci_test
🔇 Additional comments (3)
test-integration/test-chainlink/tests/ix_remote_account_provider.rs (2)

6-6: Import migration completed correctly.

The import has been properly updated to use ChainUpdatesClient, which is the new unified enum that supports both WebSocket and Laser gRPC clients.


24-26: Function signature correctly updated.

The return type properly reflects the migration to SubMuxClient<ChainUpdatesClient>, maintaining consistency with the new client enum.

magicblock-chainlink/src/chainlink/mod.rs (1)

20-22: Imports align with the new updates backend.

Bringing chain_updates_client::ChainUpdatesClient alongside the ChainPubsubClient trait is consistent with the refactor. No issues spotted here.

V,
C,
>,
Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

Stabilize the public return type with an alias to avoid downstream churn.

Exposing SubMuxClient<ChainUpdatesClient> in the public signature leaks backend details and may force downstream changes next time the backend evolves. Add a stable alias and use it in the signature.

Apply:

@@
-    ) -> ChainlinkResult<
-        Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
-    > {
+    ) -> ChainlinkResult<
+        Chainlink<ChainRpcClientImpl, ChainUpdatesMuxClient, V, C>,
+    > {

And define the alias once in this module (near other pub uses):

@@
 pub use blacklisted_accounts::*;
 
+/// Stable alias for the multiplexed updates client to keep backend details abstract.
+pub type ChainUpdatesMuxClient = SubMuxClient<ChainUpdatesClient>;

Run to find other occurrences that could switch to the alias:


🏁 Script executed:

#!/bin/bash
rg -nP --type=rust -C1 'SubMuxClient\s*<\s*ChainUpdatesClient\s*>'

Length of output: 3562


Define and use a public type alias to stabilize the chain updates client interface.

The pattern SubMuxClient<ChainUpdatesClient> appears across 14 locations in the codebase (test-integration, magicblock-api, magicblock-chainlink, magicblock-aperture, magicblock-accounts). Exposing this concrete backend type in public signatures creates tight coupling and forces downstream changes when the implementation evolves.

Suggested approach:

Define the alias in magicblock-chainlink/src/chainlink/mod.rs:

 pub use blacklisted_accounts::*;
 
+/// Stable alias for the multiplexed updates client to keep backend details abstract.
+pub type ChainUpdatesMuxClient = SubMuxClient<ChainUpdatesClient>;

Update the public return type at line 92:

-    ) -> ChainlinkResult<
-        Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
-    > {
+    ) -> ChainlinkResult<
+        Chainlink<ChainRpcClientImpl, ChainUpdatesMuxClient, V, C>,
+    > {

Additional refactoring opportunities: Consider updating other public signatures in magicblock-chainlink/src/remote_account_provider/mod.rs (lines 172, 184, 275, 302, 960) and similar public exports across other modules to use the alias for consistency.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>,
Chainlink<ChainRpcClientImpl, ChainUpdatesMuxClient, V, C>,
🤖 Prompt for AI Agents
magicblock-chainlink/src/chainlink/mod.rs around line 92: define a public type
alias such as pub type ChainUpdatesBackend = SubMuxClient<ChainUpdatesClient>;
then replace the exposed concrete type usage at line 92
(Chainlink<ChainRpcClientImpl, SubMuxClient<ChainUpdatesClient>, V, C>) with the
alias (Chainlink<ChainRpcClientImpl, ChainUpdatesBackend, V, C>) to decouple the
public API from the concrete implementation; also scan and update other public
signatures in magicblock-chainlink/src/remote_account_provider/mod.rs (lines
172, 184, 275, 302, 960) and other modules cited to use the same alias to
stabilize the interface.

Comment on lines 33 to +34
RemoteAccountProvider::<
ChainRpcClientImpl,
SubMuxClient<ChainPubsubClientImpl>,
SubMuxClient<ChainUpdatesClient>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Type instantiation is correct, but verify main implementation file is fully migrated.

The type parameter update in this test file is correct and consistent. However, based on previous review findings, the main implementation file magicblock-chainlink/src/remote_account_provider/mod.rs may still have incomplete migration with three impl blocks (around lines 159, 940, and 952) still referencing ChainPubsubClientImpl instead of ChainUpdatesClient.

Please verify that all impl blocks in the main file have been updated to prevent potential type mismatches or compilation errors.

Run the following script to verify that no remaining ChainPubsubClientImpl references exist in impl blocks:


🏁 Script executed:

#!/bin/bash
# Check for any remaining ChainPubsubClientImpl references in the main implementation
echo "=== Checking for ChainPubsubClientImpl in impl blocks ==="
rg -nP 'impl.*ChainPubsubClientImpl' magicblock-chainlink/src/remote_account_provider/mod.rs

echo ""
echo "=== All RemoteAccountProvider impl signatures ==="
rg -n -A2 'impl.*RemoteAccountProvider' magicblock-chainlink/src/remote_account_provider/mod.rs | head -50

echo ""
echo "=== Verify ChainUpdatesClient is used consistently ==="
rg -n 'SubMuxClient<ChainUpdatesClient>' magicblock-chainlink/src/remote_account_provider/mod.rs

Length of output: 870


I need to inspect the impl block at line 940 more closely to understand the full scope of what needs to be updated.


🏁 Script executed:

#!/bin/bash
# Get context around the problematic impl block at line 940
echo "=== Context around line 940 impl block ==="
sed -n '935,975p' magicblock-chainlink/src/remote_account_provider/mod.rs

echo ""
echo "=== Check if there are other impl blocks that still need updating ==="
rg -n 'impl.*RemoteAccountProvider.*ChainPubsubClientImpl' magicblock-chainlink/src/remote_account_provider/mod.rs

Length of output: 308


I need to find the correct path to the implementation file first.


🏁 Script executed:

#!/bin/bash
# Find the remote_account_provider file
echo "=== Locating remote_account_provider implementation ==="
find . -name "mod.rs" -path "*remote_account_provider*" 2>/dev/null

echo ""
echo "=== Alternative: search for ChainPubsubClientImpl references ==="
rg -l 'ChainPubsubClientImpl' --type rust 2>/dev/null | head -10

Length of output: 441


🏁 Script executed:

#!/bin/bash
# Get context around the problematic impl block at line 940
echo "=== Context around line 940 impl block ==="
sed -n '935,975p' ./magicblock-chainlink/src/remote_account_provider/mod.rs

echo ""
echo "=== Count of ChainPubsubClientImpl references in main file ==="
rg -c 'ChainPubsubClientImpl' ./magicblock-chainlink/src/remote_account_provider/mod.rs

Length of output: 1025


🏁 Script executed:

#!/bin/bash
# Check if the old impl blocks are actually used anywhere
echo "=== Search for RemoteAccountProvider instantiations with ChainPubsubClientImpl ==="
rg -n 'RemoteAccountProvider.*ChainPubsubClientImpl' --type rust -g '!mod.rs' | head -20

echo ""
echo "=== Check test file for what type it actually instantiates ==="
sed -n '30,40p' ./test-integration/test-chainlink/tests/ix_remote_account_provider.rs

echo ""
echo "=== Verify no compilation would fail due to ambiguous impl blocks ==="
rg -n 'RemoteAccountProvider::<' ./test-integration/test-chainlink/tests/ix_remote_account_provider.rs

Length of output: 606


Remove unused old impl blocks in main implementation file.

The test file changes are correct—they properly use SubMuxClient<ChainUpdatesClient>. However, the main implementation file still contains two dead code impl blocks for the old type that should be removed:

  • Line 940-942: impl RemoteAccountProvider<ChainRpcClientImpl, ChainPubsubClientImpl> (unused)
  • Line 951-967: impl RemoteAccountProvider<ChainRpcClientImpl, SubMuxClient<ChainPubsubClientImpl>> (unused)

These blocks are never instantiated anywhere in the codebase. Remove them to complete the migration and eliminate confusion. Keep only the impl block at line 960+ that uses SubMuxClient<ChainUpdatesClient>.

🤖 Prompt for AI Agents
In test-integration/test-chainlink/tests/ix_remote_account_provider.rs around
lines 32-34, remove the two dead/unused impl blocks in the main implementation
file: delete the impl block at lines 940-942 (impl
RemoteAccountProvider<ChainRpcClientImpl, ChainPubsubClientImpl>) and the impl
block at lines 951-967 (impl RemoteAccountProvider<ChainRpcClientImpl,
SubMuxClient<ChainPubsubClientImpl>>); ensure you keep the existing impl block
at line ~960+ that uses SubMuxClient<ChainUpdatesClient>, run cargo check/tests
to confirm no references remain, and update any imports/doc comments if they now
reference the removed types.

}
}

pub fn is_helius_laser_url(url: &str) -> bool {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think having a separate config instead of reusing the ws-url is clearer and less confusing. It also leaves room to connect to both in the future for redundancy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants